/**
 * @class 2D实体父类
 * @author DuskyHuang 圣子
 * @description 被系统管理的实体（E）
*/

import { _decorator, Node, UITransform, UIOpacity, Component, Vec3 } from 'cc';
import { ISizeLike, Size, Vec2, IVec2Like } from 'cc';
import { traverse } from '../../utils';
const { ccclass } = _decorator;

@ccclass('cfw.Entity2D')
export default abstract class Entity2D extends Component {

    /** x坐标 */
    public get x(): num.px { return this.node.position.x; }
    public set x(arg: num.px) { const { y, z } = this.node.position; this.node.setPosition(arg, y, z); }

    /** y坐标 */
    public get y(): num.px { return this.node.position.y; }
    public set y(arg: num.px) { const { x, z } = this.node.position; this.node.setPosition(x, arg, z); }

    /** 宽度 */
    public get w(): num.px { return this.getComponent(UITransform)?.width; }
    public set w(arg: num.px) { this.getComponent(UITransform).width = arg; }

    /** 高度 */
    public get h(): num.px { return this.getComponent(UITransform)?.height; }
    public set h(arg: num.px) { this.getComponent(UITransform).height = arg; }

    /** 尺寸 */
    public get size(): Readonly<Size> { return this.getComponent(UITransform)?.contentSize; }
    public set size(args: ISizeLike) { this.getComponent(UITransform).setContentSize(args.width, args.height); }

    /** 透明度 */
    public get alpha(): num.pct { return this.getComponent(UIOpacity)?.opacity ?? 1; }
    public set alpha(arg: num.pct) { (this.getComponent(UIOpacity) ?? this.addComponent(UIOpacity)).opacity = arg * 255; }

    /** 
     * 变换2D实体到另一个节点下
     * @param parent 新的父节点
     * @param offset 并产生平移，默认不偏移
     */
    public traverse(parent: Node, offset?: IVec2Like): void {
        if (parent instanceof Node && this.node.parent !== parent) {
            traverse(this.node, parent, offset)
        }
    }

    /** 
     * 2D实体到目标距离
     * @param target 目标2D实体
     * @param to 目标节点
     * @param point 目标位置点
     * @param x 目标坐标x
     * @param y 目标坐标y
     * @return 距离值
     */
    public distance(target: Entity2D): num.px;
    public distance(point: IVec2Like): num.px;
    public distance(to: Node): num.px;
    public distance(x: num.px, y: num.px): num.px;
    public distance(arg: Entity2D | Node | IVec2Like | num.px, y?: num.px): num.px {
        return Entity2D.distance(this, arg as any, y);
    }

    public static distance(from: Entity2D, target: Entity2D): num.px;
    public static distance(from: Entity2D, to: Node): num.px;
    public static distance(from: Entity2D, point: Entity2D): num.px;
    public static distance(from: Entity2D, x: num.px, y: num.px,): num.px;
    public static distance(from: Entity2D, arg: Entity2D | Node | IVec2Like | num.px, y?: num.px): num.px {
        Vec2.copy(v2a, arg instanceof Entity2D ? arg.node.worldPosition : arg instanceof Node ?
            arg.worldPosition : (isObject(arg) && 'x' in arg) ? arg : v2a.set(arg, y));
        return Vec2.distance(v2a, Vec2.set(v2b, from.node.worldPosition.x, from.node.worldPosition.y));
    }
}

const v2a = new Vec2;
const v2b = new Vec2;
const v3a = new Vec3;